<template>
  <div>
    <el-card>
      <h1 style="width: 20%; margin: auto">算法介绍</h1>
      <p style="font-size: large">
        时间序列分析是统计学和数据科学中的重要领域，主要用于研究随时间变化的数据规律、预测未来趋势和识别潜在模式。它记录按时间戳顺序的一系列观测值，趋势，季节性，周期性，噪声等等是它的核心要素。通过这些核心要素，便可以提取时间依赖模式并预测未来。通过综合传统与深度学习模型，时间序列分析在精度和适用性上持续提升，但需根据具体场景权衡模型复杂度与解释性。
      </p>
    </el-card>

    <el-card>
      <h1 style="width: 20%; margin: auto">数据集选择</h1>
      <el-select v-model="courseSelect" filterable placeholder="请选择课程" style="width: 20%; margin: 2%">
        <el-option
          v-for="item in courseOptions"
          :key="item.subId"
          :label="item.subName"
          :value="item.subId">
        </el-option>
      </el-select>
      <el-select v-model="teacherSelect" filterable placeholder="请选择教师" style="width: 20%; margin: 2%">
        <el-option
          v-for="item in teacherOptions"
          :key="item.teacherId"
          :label="item.teacherName"
          :value="item.teacherId">
        </el-option>
      </el-select>
      <el-button type="primary" @click="timeAnalyse" style="width: 10%; margin: 2%">开始分析</el-button>
    </el-card>

    <el-card v-if="show">
      <h1 style="width: 20%; margin: auto">分析图表</h1>
      <div
        ref="myChart"
        id="myChart"
        class="chart-box"
        :style="{ width: '800px', height: '800px' }"
        style="margin: auto"
      >
      </div>
    </el-card>

    <el-card v-if="show">
      <h1 style="width: 20%; margin: auto">分析结果说明</h1>
      <el-table
        :data="valuesTable"
        style="width: 100%"
      >
        <el-table-column
          prop="time"
          label="评教时间"
          sortable
          style="width: 25%; margin: auto"
        />
        <el-table-column
          prop="count"
          label="评教督导数量"
          sortable
          style="width: 25%; margin: auto"
        />
        <el-table-column
          prop="courseRange"
          label="督导评教成绩范围"
          style="width: 25%; margin: auto"
        />
        <el-table-column
          prop="studentAvg"
          label="督导评教平均分"
          sortable
          style="width: 25%; margin: auto"
        />
      </el-table>
    </el-card>
  </div>
</template>

<script>
import * as echarts from 'echarts'
import axios from 'axios'

export default {
  data() {
    return {
      timeStats: [],
      timeSet: [],
      courseOptions: [],
      teacherOptions: [],
      courseSelect: '',
      teacherSelect: '',
      valuesTable: [],
      show: false
    }
  },
  methods: {
    async getCourseOptions() {
      await axios.get('http://localhost:8080/course/get_all').then((res) => {
        for (let i = 0; i < res.data.data.length; i++) {
          this.courseOptions[i] = {
            subName: '',
            subId: ''
          }
          this.courseOptions[i].subName = res.data.data[i].subName
          this.courseOptions[i].subId = res.data.data[i].subId
        }
        this.courseOptions[this.courseOptions.length - 1].subName = 'ALL'
        this.courseOptions[this.courseOptions.length - 1].subId = 'ALL'
        this.courseSelect = '请选择课程'
      })
    },
    async getTeacherOptions() {
      await axios.get('http://localhost:8080/teacher/get_all').then((res) => {
        for (let i = 0; i < res.data.data.length; i++) {
          this.teacherOptions[i] = {
            teacherName: '',
            teacherId: ''
          }
          this.teacherOptions[i].teacherName = res.data.data[i].teacherName
          this.teacherOptions[i].teacherId = res.data.data[i].teacherId
        }
        this.teacherOptions[this.teacherOptions.length - 1].teacherName = 'ALL'
        this.teacherOptions[this.teacherOptions.length - 1].teacherId = 'ALL'
        this.teacherSelect = '请选择教师'
      })
    },
    async getTimeScoreSet() {
      if (this.courseSelect === '请选择课程' || this.courseSelect === 'ALL') {
        this.courseSelect = null
      }
      if (this.teacherSelect === '请选择教师' || this.teacherSelect === 'ALL') {
        this.teacherSelect = null
      }

      const params = new URLSearchParams()
      params.append('teacherId', this.teacherSelect)
      params.append('subId', this.courseSelect)

      await axios.post('http://localhost:8080/time_score/time_sup', params, {
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded' // 必须指定 Content-Type
        }
      }).then((res) => {
        // 未查询到相关数据进行提示
        if (res.data.success === false) {
          this.$message.error('未查询到相关数据')
          this.show = false
          return
        } else {
          this.show = true
        }

        let index = 0
        this.timeSet = []
        for (let i = 0; i < res.data.data.length; i++) {
          if (res.data.data[i].evaTime === null || res.data.data[i].evaTime === '') {
            continue
          }
          this.timeSet[index] = {
            evaTime: '',
            score: 0
          }
          this.timeSet[index].evaTime = res.data.data[i].evaTime
          this.timeSet[index].score = Number(res.data.data[i].score).toFixed(1)
          index += 1
        }
      })
    },
    async timeAnalyse() {
      await this.getTimeScoreSet()
      if (this.timeSet.length === 0) {
        return
      }

      const chart = echarts.init(document.getElementById('myChart'))

      // 创建一个二维数组
      const dateArray = []
      const scoreArray = []
      const array = new Array(this.timeSet.length)
      for (let i = 0; i < array.length; i++) {
        // 为子数组赋值（例如随机数）
        if (this.timeSet[i].evaTime !== '' || this.timeSet[i].evaTime !== null) {
          array[i] = new Array(2) // 每行创建长度为2的子数组
          array[i][0] = this.timeSet[i].evaTime
          array[i][1] = parseFloat(this.timeSet[i].score)
          dateArray[i] = array[i][0]
          scoreArray[i] = array[i][1]
        }
      }
      this.timeStats = this.groupByDateSplit(array)
      console.log(this.timeStats)

      // 找到坐标轴范围
      const timeRange = this.findMinMaxDates(dateArray)
      const scoreRange = this.findMinMaxScores(scoreArray)

      // 转换为时间戳格式（ECharts 要求数值或时间戳）
      const formattedData = array.map(item => [
        new Date(item[0]).getTime(), // 时间转为时间戳
        parseFloat(item[1]) // 分数
      ])

      this.valuesTable = []
      const line = []
      for (let i = 0; i < this.timeStats.length; ++i) {
        this.valuesTable[i] = {
          time: this.timeStats[i].year + '年' + this.timeStats[i].month + '月' + this.timeStats[i].day + '日',
          count: this.timeStats[i].count,
          courseRange: '[' + this.timeStats[i].minScore + '~' + this.timeStats[i].maxScore + ']',
          studentAvg: this.timeStats[i].avgScore
        }

        line[i] = []
        line[i] = [this.timeStats[i].date, this.timeStats[i].avgScore]
      }

      console.log(formattedData)
      // 配置项
      const option = {
        xAxis: {
          type: 'time', // 时间轴类型
          name: '日期',
          axisLabel: {
            formatter: '{yyyy}-{MM}-{dd}', // 显示年月日
            rotate: 45 // 标签旋转45度防重叠
          },
          min: timeRange.min,
          max: timeRange.max
        },
        yAxis: {
          type: 'value',
          name: '督导评教分数',
          min: scoreRange.min,
          max: scoreRange.max
        },
        series: [{
          type: 'scatter',
          data: formattedData,
          symbolSize: 10,
          itemStyle: { color: '#5470C6' }
        }, {
          type: 'line',
          data: line,
          smooth: 1, // 平滑系数（0-1）
          lineStyle: { color: '#FF0000' }
        }],
        tooltip: {
          trigger: 'item',
          formatter: (params) => {
            const date = new Date(params.value[0])
            const studentCount = this.getStudentsNum(date, params.value[1])
            return `日期：${date.toLocaleDateString()}<br>分数：${params.value[1]}<br>学生数量：${studentCount.toString()}`
          }
        }
      }

      chart.setOption(option)
    },
    getStudentsNum(date, score) {
      let index = 0
      for (let i = 0; i < this.timeSet.length; i++) {
        const [year, month, day] = this.timeSet[i].evaTime.split('-')

        if (parseInt(date.getDate()) === parseInt(day) && parseInt(date.getMonth() + 1) === parseInt(month) && parseInt(date.getFullYear()) === parseInt(year) && parseFloat(this.timeSet[i].score) === parseFloat(score)) {
          ++index
        }
      }
      return index
    },
    findMinMaxDates(dateArray) {
      // 将日期字符串转换为对象（包含原字符串和时间戳）
      const dateEntries = dateArray.map(original => {
        // 分割年月日并补零
        if (original === null || original === '') {
          return { original }
        }
        const [year, month, day] = original.split('-')
        const formatted = `${year}-${month.padStart(2, '0')}-${day.padStart(2, '0')}`
        const timestamp = Date.parse(formatted)

        // 检查是否为有效日期
        if (isNaN(timestamp)) {
          throw new Error(`无效日期格式: ${original}`)
        }
        return { original, timestamp }
      })

      // 找到最大和最小时间戳对应的原始字符串
      let min = dateEntries[0]
      let max = dateEntries[0]
      dateEntries.forEach(entry => {
        if (entry.timestamp < min.timestamp) min = entry
        if (entry.timestamp > max.timestamp) max = entry
      })

      return { max: max.original, min: min.original }
    },
    findMinMaxScores(scoreArray) {
      // 找到最大和最小时间戳对应的原始字符串
      let min = scoreArray[0]
      let max = scoreArray[0]
      scoreArray.forEach(entry => {
        if (entry < min) min = entry
        if (entry > max) max = entry
      })

      return { max: max, min: min }
    },
    groupByDateSplit(data) {
      data.sort((a, b) =>
        new Date(a[0]).getTime() - new Date(b[0]).getTime()
      )

      // 按日期分组并拆分年月日
      let i = 0
      const grouped = data.reduce((acc, item) => {
        const dateKey = item[0]
        if (!acc[dateKey]) {
          // 拆分年月日，并移除前导零（如 '05' → '5'）
          if (item[0] === null || item[0] === '') {
            return
          }
          const [year, month, day] = item[0].split('-')
          acc[dateKey] = {
            year: year,
            month: String(Number(month)), // 去掉前导零
            day: String(Number(day)), // 去掉前导零
            totalScore: 0,
            count: 0,
            maxScore: -Infinity,
            minScore: Infinity,
            index: i
          }
          i++
        }

        // 更新统计值
        const group = acc[dateKey]
        group.date = new Date(item[0]).getTime()
        group.totalScore += item[1]
        group.count++
        group.maxScore = Math.max(group.maxScore, item[1])
        group.minScore = Math.min(group.minScore, item[1])
        return acc
      }, {})

      // 计算平均分并返回数组
      return Object.values(grouped).map(group => ({
        ...group,
        avgScore: Number((group.totalScore / group.count).toFixed(2))
      }))
    }
  },
  mounted() {
    this.getCourseOptions()
    this.getTeacherOptions()
  }
}
</script>

<style>
.chart-container {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 20px;
  padding: 20px;
  max-width: 1200px;
  margin: 0 auto;
}
.chart-box {
  height: 800px;
  width: 800px;
  border: 1px solid #eee;
  padding: 15px;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
</style>
